<!DOCTYPE html>



  


<html class="theme-next muse use-motion" lang>
<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
















  
  
  <link href="/blog/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">







<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/blog/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/blog/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="设计模式,">





  <link rel="alternate" href="/blog/atom.xml" title="编程那点事" type="application/atom+xml">






<meta name="description" content="模块化模式模块模块是任何健壮的应用程序体系结构不可或缺的一部分，特点是有助于保持应用项目的代码单元既能清晰地分离又有组织。 在JavaScript中，实现模块有几个选项，他们包括：  模块化模式 对象表示法 AMD模块 CommonJS 模块 ECMAScript Harmony 模块  我们在书中后面的现代模块化JavaScript设计模式章节中将探讨这些选项中的最后三个。 模块化模式是基于对象">
<meta name="keywords" content="设计模式">
<meta property="og:type" content="article">
<meta property="og:title" content="JavaScript 模块化模式">
<meta property="og:url" content="https://lhweb.gitee.io/blog/2018/09/27/JavaScript-模块化模式/index.html">
<meta property="og:site_name" content="编程那点事">
<meta property="og:description" content="模块化模式模块模块是任何健壮的应用程序体系结构不可或缺的一部分，特点是有助于保持应用项目的代码单元既能清晰地分离又有组织。 在JavaScript中，实现模块有几个选项，他们包括：  模块化模式 对象表示法 AMD模块 CommonJS 模块 ECMAScript Harmony 模块  我们在书中后面的现代模块化JavaScript设计模式章节中将探讨这些选项中的最后三个。 模块化模式是基于对象">
<meta property="og:locale" content="default">
<meta property="og:updated_time" content="2019-10-03T05:53:45.847Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="JavaScript 模块化模式">
<meta name="twitter:description" content="模块化模式模块模块是任何健壮的应用程序体系结构不可或缺的一部分，特点是有助于保持应用项目的代码单元既能清晰地分离又有组织。 在JavaScript中，实现模块有几个选项，他们包括：  模块化模式 对象表示法 AMD模块 CommonJS 模块 ECMAScript Harmony 模块  我们在书中后面的现代模块化JavaScript设计模式章节中将探讨这些选项中的最后三个。 模块化模式是基于对象">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Muse',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Author'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://lhweb.gitee.io/blog/2018/09/27/JavaScript-模块化模式/">





  <title>JavaScript 模块化模式 | 编程那点事</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="default">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">编程那点事</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/blog/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br>
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/blog/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
            
            Archives
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://lhweb.gitee.io/blog/blog/2018/09/27/JavaScript-模块化模式/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="lhweb">
      <meta itemprop="description" content>
      <meta itemprop="image" content="/blog/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="编程那点事">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">JavaScript 模块化模式</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-09-27T07:11:07+08:00">
                2018-09-27
              </time>
            

            

            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">In</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/blog/categories/javascript/" itemprop="url" rel="index">
                    <span itemprop="name">javascript</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="模块化模式"><a href="#模块化模式" class="headerlink" title="模块化模式"></a>模块化模式</h1><h1 id="模块"><a href="#模块" class="headerlink" title="模块"></a>模块</h1><p>模块是任何健壮的应用程序体系结构不可或缺的一部分，特点是有助于保持应用项目的代码单元既能清晰地分离又有组织。</p>
<p>在JavaScript中，实现模块有几个选项，他们包括：</p>
<ul>
<li>模块化模式</li>
<li>对象表示法</li>
<li>AMD模块</li>
<li>CommonJS 模块</li>
<li>ECMAScript Harmony 模块</li>
</ul>
<p>我们在书中后面的现代模块化JavaScript设计模式章节中将探讨这些选项中的最后三个。</p>
<p>模块化模式是基于对象的文字部分，所以首先对于更新我们对它们的知识是很有意义的。</p>
<h1 id="对象字面值"><a href="#对象字面值" class="headerlink" title="对象字面值"></a>对象字面值</h1><p>在对象字面值的标记里，一个对象被描述为一组以逗号分隔的名称/值对括在大括号（{}）的集合。对象内部的名称可以是字符串或是标记符后跟着一个冒号”:”。在对象里最后一个名称/值对不应该以”,”为结束符，因为这样会导致错误。<br><figure class="highlight actionscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> myObjectLiteral = &#123;</span><br><span class="line"></span><br><span class="line">    variableKey: variableValue,</span><br><span class="line"></span><br><span class="line">    functionKey: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="comment">// ...</span></span><br><span class="line">    &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p>
<p>对象字面值不要求使用新的操作实例，但是不能够在结构体开始使用，因为打开”{“可能被解释为一个块的开始。在对象外新的成员会被加载，使用分配如下：smyModule.property = “someValue”; 下面我们可以看到一个更完整的使用对象字面值定义一个模块的例子：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> myModule = &#123;</span><br><span class="line"></span><br><span class="line">  myProperty: <span class="string">"someValue"</span>,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 对象字面值包含了属性和方法（properties and methods）.</span></span><br><span class="line">  <span class="comment">// 例如，我们可以定义一个模块配置进对象：</span></span><br><span class="line">  myConfig: &#123;</span><br><span class="line">    useCaching: <span class="literal">true</span>,</span><br><span class="line">    language: <span class="string">"en"</span></span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 非常基本的方法</span></span><br><span class="line">  myMethod: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log( <span class="string">"Where in the world is Paul Irish today?"</span> );</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 输出基于当前配置（&lt;span&gt;configuration&lt;/span&gt;）的一个值</span></span><br><span class="line">  myMethod2: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log( <span class="string">"Caching is:"</span> + ( <span class="keyword">this</span>.myConfig.useCaching ) ? <span class="string">"enabled"</span> : <span class="string">"disabled"</span> );</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 重写当前的配置（configuration）</span></span><br><span class="line">  myMethod3: <span class="function"><span class="keyword">function</span>(<span class="params"> newConfig </span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> ( <span class="keyword">typeof</span> newConfig === <span class="string">"object"</span> ) &#123;</span><br><span class="line">      <span class="keyword">this</span>.myConfig = newConfig;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="keyword">this</span>.myConfig.language);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出: Where in the world is Paul Irish today?</span></span><br><span class="line">myModule.myMethod();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出: enabled</span></span><br><span class="line">myModule.myMethod2();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出: fr</span></span><br><span class="line">myModule.myMethod3(&#123;</span><br><span class="line">  language: <span class="string">"fr"</span>,</span><br><span class="line">  useCaching: <span class="literal">false</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p>使用对象字面值可以协助封装和组织你的代码。如果你想近一步了解对象字面值可以阅读 Rebecca Murphey 写过的关于此类话题的更深入的文章(depth)。</p>
<p>也就是说，如果我们选择了这种技术，我们可能对模块模式有同样的兴趣。即使使用对象字面值，但也只有一个函数的返回值。</p>
<h1 id="模块化模式-1"><a href="#模块化模式-1" class="headerlink" title="模块化模式"></a>模块化模式</h1><p>模块化模式最初被定义为一种对传统软件工程中的类提供私有和公共封装的方法。</p>
<p>在JavaScript中，模块化模式用来进一步模拟类的概念，通过这样一种方式：我们可以在一个单一的对象中包含公共/私有的方法和变量，从而从全局范围中屏蔽特定的部分。这个结果是可以减少我们的函数名称与在页面中其他脚本区域定义的函数名称冲突的可能性。</p>
<h2 id="私有信息"><a href="#私有信息" class="headerlink" title="私有信息"></a>私有信息</h2><p>模块模式使用闭包的方式来将”私有信息”,状态和组织结构封装起来。提供了一种将公有和私有方法，变量封装混合在一起的方式，这种方式防止内部信息泄露到全局中，从而避免了和其它开发者接口发生冲图的可能性。在这种模式下只有公有的API 会返回，其它将全部保留在闭包的私有空间中。</p>
<p>这种方法提供了一个比较清晰的解决方案，在只暴露一个接口供其它部分使用的情况下，将执行繁重任务的逻辑保护起来。这个模式非常类似于立即调用函数式表达式(IIFE-查看命名空间相关章节获取更多信息)，但是这种模式返回的是对象，而立即调用函数表达式返回的是一个函数。</p>
<p>需要注意的是，在javascript事实上没有一个显式的真正意义上的”私有性”概念，因为与传统语言不同，javascript没有访问修饰符。从技术上讲，变量不能被声明为公有的或者私有的，因此我们使用函数域的方式去模拟这个概念。在模块模式中，因为闭包的缘故，声明的变量或者方法只在模块内部有效。在返回对象中定义的变量或者方法可以供任何人使用。</p>
<h2 id="历史"><a href="#历史" class="headerlink" title="历史"></a>历史</h2><p>从历史角度来看，模块模式最初是在2003年由一群人共同发展出来的，这其中包括Richard Cornford。后来通过Douglas Crockford的演讲，逐渐变得流行起来。另外一件事情是，如果你曾经用过雅虎的YUI库，你会看到其中的一些特性和模块模式非常类似，而这种情况的原因是在创建YUI框架的时候，模块模式极大的影响了YUI的设计。</p>
<h2 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h2><p>下面这个例子通过创建一个自包含的模块实现了模块模式。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> testModule = (<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> counter = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line"></span><br><span class="line">    incrementCounter: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="keyword">return</span> counter++;</span><br><span class="line">    &#125;,</span><br><span class="line"></span><br><span class="line">    resetCounter: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="built_in">console</span>.log( <span class="string">"counter value prior to reset: "</span> + counter );</span><br><span class="line">      counter = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">&#125;)();</span><br><span class="line"></span><br><span class="line"><span class="comment">// Usage:</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Increment our counter</span></span><br><span class="line">testModule.incrementCounter();</span><br><span class="line"></span><br><span class="line"><span class="comment">// Check the counter value and reset</span></span><br><span class="line"><span class="comment">// Outputs: 1</span></span><br><span class="line">testModule.resetCounter();</span><br></pre></td></tr></table></figure></p>
<p>在这里我们看到，其它部分的代码不能直接访问我们的incrementCounter() 或者 resetCounter()的值。counter变量被完全从全局域中隔离起来了，因此其表现的就像一个私有变量一样，它的存在只局限于模块的闭包内部，因此只有两个函数可以访问counter。我们的方法是有名字空间限制的，因此在我们代码的测试部分，我们需要给所有函数调用前面加上模块的名字(例如”testModule”)。</p>
<p>当使用模块模式时，我们会发现通过使用简单的模板，对于开始使用模块模式非常有用。下面是一个模板包含了命名空间，公共变量和私有变量。<br><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> myNamespace = (<span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> myPrivateVar, myPrivateMethod;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// A private counter variable</span></span><br><span class="line">  myPrivateVar = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// A private function which logs any arguments</span></span><br><span class="line">  myPrivateMethod = <span class="function"><span class="keyword">function</span><span class="params">( foo )</span> </span>&#123;</span><br><span class="line">      console.log( foo );</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// A public variable</span></span><br><span class="line">    myPublicVar: <span class="string">"foo"</span>,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// A public function utilizing privates</span></span><br><span class="line">    myPublicFunction: <span class="function"><span class="keyword">function</span><span class="params">( bar )</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// Increment our private counter</span></span><br><span class="line">      myPrivateVar++;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// Call our private method using bar</span></span><br><span class="line">      myPrivateMethod( bar );</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure></p>
<p>看一下另外一个例子，下面我们看到一个使用这种模式实现的购物车。这个模块完全自包含在一个叫做basketModule 全局变量中。模块中的购物车数组是私有的，应用的其它部分不能直接读取。只存在与模块的闭包中，因此只有可以访问其域的方法可以访问这个变量。<br><figure class="highlight actionscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> basketModule = (<span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// privates</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> basket = [];</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">doSomethingPrivate</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">doSomethingElsePrivate</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Return an object exposed to the public</span></span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Add items to our basket</span></span><br><span class="line">    addItem: <span class="function"><span class="keyword">function</span><span class="params">( values )</span> </span>&#123;</span><br><span class="line">      basket.push(values);</span><br><span class="line">    &#125;,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Get the count of items in the basket</span></span><br><span class="line">    getItemCount: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">return</span> basket.length;</span><br><span class="line">    &#125;,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Public alias to a  private function</span></span><br><span class="line">    doSomething: doSomethingPrivate,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Get the total value of items in the basket</span></span><br><span class="line">    getTotal: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> q = <span class="keyword">this</span>.getItemCount(),</span><br><span class="line">          p = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">while</span> (q--) &#123;</span><br><span class="line">        p += basket[q].price;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">return</span> p;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;());</span><br></pre></td></tr></table></figure></p>
<p>在模块内部，你可能注意到我们返回了应外一个对象。这个自动赋值给了basketModule 因此我们可以这样和这个对象交互。<br><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// basketModule returns an object with a public API we can use</span></span><br><span class="line"></span><br><span class="line"><span class="selector-tag">basketModule</span><span class="selector-class">.addItem</span>(&#123;</span><br><span class="line">  <span class="attribute">item</span>: <span class="string">"bread"</span>,</span><br><span class="line">  <span class="attribute">price</span>: <span class="number">0.5</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">basketModule</span><span class="selector-class">.addItem</span>(&#123;</span><br><span class="line">  <span class="attribute">item</span>: <span class="string">"butter"</span>,</span><br><span class="line">  <span class="attribute">price</span>: <span class="number">0.3</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Outputs: 2</span></span><br><span class="line"><span class="selector-tag">console</span><span class="selector-class">.log</span>( basketModule.getItemCount() );</span><br><span class="line"></span><br><span class="line"><span class="comment">// Outputs: 0.8</span></span><br><span class="line"><span class="selector-tag">console</span><span class="selector-class">.log</span>( basketModule.getTotal() );</span><br><span class="line"></span><br><span class="line"><span class="comment">// However, the following will not work:</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Outputs: undefined</span></span><br><span class="line"><span class="comment">// This is because the basket itself is not exposed as a part of our</span></span><br><span class="line"><span class="comment">// the public API</span></span><br><span class="line"><span class="selector-tag">console</span><span class="selector-class">.log</span>( basketModule.basket );</span><br><span class="line"></span><br><span class="line"><span class="comment">// This also won't work as it only exists within the scope of our</span></span><br><span class="line"><span class="comment">// basketModule closure, but not the returned public object</span></span><br><span class="line"><span class="selector-tag">console</span><span class="selector-class">.log</span>( basket );</span><br></pre></td></tr></table></figure></p>
<p>上面的方法都处于basketModule 的名字空间中。</p>
<p>请注意在上面的basket模块中 域函数是如何在我们所有的函数中被封装起来的，以及我们如何立即调用这个域函数，并且将返回值保存下来。这种方式有以下的优势：</p>
<ul>
<li>可以创建只能被我们模块访问的私有函数。这些函数没有暴露出来（只有一些API是暴露出来的），它们被认为是完全私有的。</li>
<li>当我们在一个调试器中，需要发现哪个函数抛出异常的时候，可以很容易的看到调用栈，因为这些函数是正常声明的并且是命名的函数。</li>
<li>正如过去 T.J Crowder 指出的，这种模式同样可以让我们在不同的情况下返回不同的函数。我见过有开发者使用这种技巧用于执行UA（尿检，抽样检查）测试，目的是为了在他们的模块里面针对IE专门提供一条代码路径，但是现在我们也可以简单的使用特征检测达到相同的目的。</li>
</ul>
<h1 id="模块模式的变体"><a href="#模块模式的变体" class="headerlink" title="模块模式的变体"></a>模块模式的变体</h1><h2 id="Import-mixins-导入混合"><a href="#Import-mixins-导入混合" class="headerlink" title="Import mixins(导入混合)"></a>Import mixins(导入混合)</h2><p>这个变体展示了如何将全局（例如 jQuery, Underscore）作为一个参数传入模块的匿名函数。这种方式允许我们导入全局，并且按照我们的想法在本地为这些全局起一个别名。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Global module</span></span><br><span class="line"><span class="keyword">var</span> myModule = (<span class="function"><span class="keyword">function</span> (<span class="params"> jQ, _ </span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">privateMethod1</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        jQ(<span class="string">".container"</span>).html(<span class="string">"test"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">privateMethod2</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">      <span class="built_in">console</span>.log( _.min([<span class="number">10</span>, <span class="number">5</span>, <span class="number">100</span>, <span class="number">2</span>, <span class="number">1000</span>]) );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span>&#123;</span><br><span class="line">        publicMethod: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            privateMethod1();               </span><br><span class="line">        &#125;           </span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Pull in jQuery and Underscore</span></span><br><span class="line">&#125;( jQuery, _ ));</span><br><span class="line"></span><br><span class="line">myModule.publicMethod();</span><br></pre></td></tr></table></figure></p>
<h2 id="Exports（导出）"><a href="#Exports（导出）" class="headerlink" title="Exports（导出）"></a>Exports（导出）</h2><p>这个变体允许我们声明全局对象而不用使用它们，同样也支持在下一个例子中我们将会看到的全局导入的概念。<br><figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Global module</span></span><br><span class="line">var myModule = (<span class="function"><span class="keyword">function</span> <span class="params">()</span> &#123;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Module object</span></span><br><span class="line">  var <span class="function"><span class="keyword">module</span> =</span> &#123;&#125;,</span><br><span class="line">    privateVariable = <span class="string">"Hello World"</span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">privateMethod</span><span class="params">()</span> &#123;</span></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">module</span>.<span class="title">publicProperty</span> =</span> <span class="string">"Foobar"</span>;</span><br><span class="line">  <span class="function"><span class="keyword">module</span>.<span class="title">publicMethod</span> =</span> <span class="function"><span class="keyword">function</span> <span class="params">()</span> &#123;</span></span><br><span class="line">    console.<span class="built_in">log</span>( privateVariable );</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  return <span class="function"><span class="keyword">module</span>;</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">&#125;<span class="params">()</span>);</span></span><br></pre></td></tr></table></figure></p>
<p>工具箱和框架特定的模块模式实现。</p>
<h2 id="Dojo"><a href="#Dojo" class="headerlink" title="Dojo"></a>Dojo</h2><p>Dojo提供了一个方便的方法 dojo.setObject() 来设置对象。这需要将以”.”符号为第一个参数的分隔符，如：myObj.parent.child 是指定义在”myOjb”内部的一个对象“parent”，它的一个属性为”child”。使用setObject()方法允许我们设置children 的值，可以创建路径传递过程中的任何对象即使这些它们根本不存在。</p>
<p>例如，如果我们声明商店命名空间的对象basket.coreas，可以实现使用传统的方式如下：<br><figure class="highlight llvm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">var <span class="keyword">store</span> = window.<span class="keyword">store</span> || &#123;&#125;<span class="comment">;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">if ( !store["basket"] ) &#123;</span></span><br><span class="line"><span class="comment">  store.basket = &#123;&#125;;</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">if ( !store.basket["core"] ) &#123;</span></span><br><span class="line"><span class="comment">  store.basket.core = &#123;&#125;;</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">store.basket.core = &#123;</span></span><br><span class="line"><span class="comment">  // ...rest of our logic</span></span><br><span class="line"><span class="comment">&#125;;</span></span><br></pre></td></tr></table></figure></p>
<p>或使用Dojo1.7（AMD兼容的版本）及以上如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">require</span>([<span class="string">"dojo/_base/customStore"</span>], <span class="function"><span class="keyword">function</span>(<span class="params"> store </span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// using dojo.setObject()</span></span><br><span class="line">  store.setObject( <span class="string">"basket.core"</span>, (<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> basket = [];</span><br><span class="line"></span><br><span class="line">      <span class="function"><span class="keyword">function</span> <span class="title">privateMethod</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">          <span class="built_in">console</span>.log(basket);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">return</span> &#123;</span><br><span class="line">          publicMethod: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">                  privateMethod();</span><br><span class="line">          &#125;</span><br><span class="line">      &#125;;</span><br><span class="line"></span><br><span class="line">  &#125;()));</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p>欲了解更多关于dojo.setObject（）方法的信息，请参阅官方文档 documentation</p>
<h2 id="ExtJS"><a href="#ExtJS" class="headerlink" title="ExtJS"></a>ExtJS</h2><p>对于这些使用Sencha的ExtJS的人们，你们很幸运，因为官方文档包含一些例子，用于展示如何正确地在框架里面使用模块模式。</p>
<p>下面我们可以看到一个例子关于如何定义一个名字空间，然后填入一个包含有私有和公有API的模块。除了一些语义上的不同之外，这个例子和使用vanilla javascript 实现的模块模式非常相似。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// create namespace</span></span><br><span class="line">Ext.namespace(<span class="string">"myNameSpace"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// create application</span></span><br><span class="line">myNameSpace.app = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// do NOT access DOM from here; elements don't exist yet</span></span><br><span class="line">  <span class="comment">// private variables</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> btn1,</span><br><span class="line">      privVar1 = <span class="number">11</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// private functions</span></span><br><span class="line">  <span class="keyword">var</span> btn1Handler = <span class="function"><span class="keyword">function</span> (<span class="params"> button, event </span>) </span>&#123;</span><br><span class="line">      <span class="built_in">console</span>.log( <span class="string">"privVar1="</span> + privVar1 );</span><br><span class="line">      <span class="built_in">console</span>.log( <span class="string">"this.btn1Text="</span> + <span class="keyword">this</span>.btn1Text );</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// public space</span></span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    <span class="comment">// public properties, e.g. strings to translate</span></span><br><span class="line">    btn1Text: <span class="string">"Button 1"</span>,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// public methods</span></span><br><span class="line">    init: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> ( Ext.Ext2 ) &#123;</span><br><span class="line"></span><br><span class="line">        btn1 = <span class="keyword">new</span> Ext.Button(&#123;</span><br><span class="line">          renderTo: <span class="string">"btn1-ct"</span>,</span><br><span class="line">          text: <span class="keyword">this</span>.btn1Text,</span><br><span class="line">          handler: btn1Handler</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line"></span><br><span class="line">        btn1 = <span class="keyword">new</span> Ext.Button( <span class="string">"btn1-ct"</span>, &#123;</span><br><span class="line">          text: <span class="keyword">this</span>.btn1Text,</span><br><span class="line">          handler: btn1Handler</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;();</span><br></pre></td></tr></table></figure></p>
<h2 id="YUI"><a href="#YUI" class="headerlink" title="YUI"></a>YUI</h2><p>类似地，我们也可以使用YUI3来实现模块模式。下面的例子很大程度上是基于原始由Eric Miraglia实现的YUI本身的模块模式，但是和vanillla Javascript 实现的版本比较起来差异不是很大。<br><figure class="highlight monkey"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">Y.namespace( <span class="string">"store.basket"</span> ) = (<span class="function"><span class="keyword">function</span> (</span>) &#123;</span><br><span class="line"></span><br><span class="line">    var myPrivateVar, myPrivateMethod;</span><br><span class="line"></span><br><span class="line">    // <span class="keyword">private</span> variables:</span><br><span class="line">    myPrivateVar = <span class="string">"I can be accessed only within Y.store.basket."</span>;</span><br><span class="line"></span><br><span class="line">    // <span class="keyword">private</span> <span class="function"><span class="keyword">method</span>:</span></span><br><span class="line">    myPrivateMethod = <span class="function"><span class="keyword">function</span> (</span>) &#123;</span><br><span class="line">        Y.<span class="built_in">log</span>( <span class="string">"I can be accessed only from within YAHOO.store.basket"</span> );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        myPublicProperty: <span class="string">"I'm a public property."</span>,</span><br><span class="line"></span><br><span class="line">        myPublicMethod: <span class="function"><span class="keyword">function</span> (</span>) &#123;</span><br><span class="line">            Y.<span class="built_in">log</span>( <span class="string">"I'm a public method."</span> );</span><br><span class="line"></span><br><span class="line">            // Within basket, I can access <span class="string">"private"</span> vars <span class="literal">and</span> methods:</span><br><span class="line">            Y.<span class="built_in">log</span>( myPrivateVar );</span><br><span class="line">            Y.<span class="built_in">log</span>( myPrivateMethod() );</span><br><span class="line"></span><br><span class="line">            // The native scope of myPublicMethod is store so we can</span><br><span class="line">            // access <span class="keyword">public</span> members using <span class="string">"this"</span>:</span><br><span class="line">            Y.<span class="built_in">log</span>( this.myPublicProperty );</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure></p>
<h2 id="jQuery"><a href="#jQuery" class="headerlink" title="jQuery"></a>jQuery</h2><p>因为jQuery编码规范没有规定插件如何实现模块模式，因此有很多种方式可以实现模块模式。Ben Cherry 之间提供一种方案，因为模块之间可能存在大量的共性，因此通过使用函数包装器封装模块的定义。</p>
<p>在下面的例子中，定义了一个library 函数，这个函数声明了一个新的库，并且在新的库（例如 模块）创建的时候，自动将初始化函数绑定到document的ready上。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">library</span>(<span class="params"> module </span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  $( <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> ( <span class="built_in">module</span>.init ) &#123;</span><br><span class="line">      <span class="built_in">module</span>.init();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">module</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> myLibrary = library(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    init: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="comment">// module implementation</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;());</span><br></pre></td></tr></table></figure></p>
<h2 id="优势"><a href="#优势" class="headerlink" title="优势"></a>优势</h2><p>既然我们已经看到单例模式很有用，为什么还是使用模块模式呢？首先，对于有面向对象背景的开发者来讲，至少从javascript语言上来讲，模块模式相对于真正的封装概念更清晰。</p>
<p>其次，模块模式支持私有数据-因此，在模块模式中，公共部分代码可以访问私有数据，但是在模块外部，不能访问类的私有部分（没开玩笑！感谢David Engfer 的玩笑）。<br>缺点</p>
<p>模块模式的缺点是因为我们采用不同的方式访问公有和私有成员，因此当我们想要改变这些成员的可见性的时候，我们不得不在所有使用这些成员的地方修改代码。</p>
<p>我们也不能在对象之后添加的方法里面访问这些私有变量。也就是说，很多情况下，模块模式很有用，并且当使用正确的时候，潜在地可以改善我们代码的结构。</p>
<p>其它缺点包括不能为私有成员创建自动化的单元测试，以及在紧急修复bug时所带来的额外的复杂性。根本没有可能可以对私有成员打补丁。相反地，我们必须覆盖所有的使用存在bug私有成员的公共方法。开发者不能简单的扩展私有成员，因此我们需要记得，私有成员并非它们表面上看上去那么具有扩展性。</p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/blog/tags/设计模式/" rel="tag"># 设计模式</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/blog/2018/09/26/JavaScript-构造器模式/" rel="next" title="JavaScript 构造器模式">
                <i class="fa fa-chevron-left"></i> JavaScript 构造器模式
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/blog/2018/09/27/TypeScript-进阶篇/" rel="prev" title="TypeScript 进阶篇">
                TypeScript 进阶篇 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            Table of Contents
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            Overview
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">lhweb</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/blog/archives/">
              
                  <span class="site-state-item-count">39</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/blog/categories/index.html">
                  <span class="site-state-item-count">6</span>
                  <span class="site-state-item-name">categories</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/blog/tags/index.html">
                  <span class="site-state-item-count">25</span>
                  <span class="site-state-item-name">tags</span>
                </a>
              </div>
            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/blog/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#模块化模式"><span class="nav-number">1.</span> <span class="nav-text">模块化模式</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#模块"><span class="nav-number">2.</span> <span class="nav-text">模块</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#对象字面值"><span class="nav-number">3.</span> <span class="nav-text">对象字面值</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#模块化模式-1"><span class="nav-number">4.</span> <span class="nav-text">模块化模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#私有信息"><span class="nav-number">4.1.</span> <span class="nav-text">私有信息</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#历史"><span class="nav-number">4.2.</span> <span class="nav-text">历史</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#例子"><span class="nav-number">4.3.</span> <span class="nav-text">例子</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#模块模式的变体"><span class="nav-number">5.</span> <span class="nav-text">模块模式的变体</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Import-mixins-导入混合"><span class="nav-number">5.1.</span> <span class="nav-text">Import mixins(导入混合)</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Exports（导出）"><span class="nav-number">5.2.</span> <span class="nav-text">Exports（导出）</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Dojo"><span class="nav-number">5.3.</span> <span class="nav-text">Dojo</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ExtJS"><span class="nav-number">5.4.</span> <span class="nav-text">ExtJS</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#YUI"><span class="nav-number">5.5.</span> <span class="nav-text">YUI</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#jQuery"><span class="nav-number">5.6.</span> <span class="nav-text">jQuery</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#优势"><span class="nav-number">5.7.</span> <span class="nav-text">优势</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">lhweb</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Muse</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=5.1.4"></script>



  
  

  
  <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
